⚡ ⏰

触发器和事件

让数据库学会"自己干活"的两种方式

🌿 本章重在理解,不是考试重点 —— 跟着读一遍,记住几个画面就够了
📌 这节课你只需记住 4 件事
1触发器:数据一动,它就自动反应
2事件:时间一到,它就自动执行
3触发器里的 NEW / OLD 怎么用
4两者的区别:一个看数据,一个看时间

💡 上课前先想象两个再普通不过的场景:

📝 学生选了门新课,成绩还没出。系统希望 自动把成绩填成 0,而不是留个空。
🧹 临时表里堆了一堆垃圾数据。希望 每周自动清空一次,不用人记着去删。

这两件事,都不需要谁守在电脑前手动操作 —— 数据库完全可以自己干。本章就讲实现它们的两个工具:

👉 触发器(TRIGGER)管"数据一变就反应";事件(EVENT)管"时间一到就执行"。就这么两件事。

1

触发器:数据的"自动反应"

表里数据一被动,它就替你跑一段预设好的 SQL

先用一句话 + 一盏灯理解它

📖 定义

触发器是一段"挂"在表上的 SQL。当你对这张表做 INSERT / UPDATE / DELETE 时,它会被自动触发执行,不需要你手动去调用。

🌰 把它想成"门口的红外感应灯"

① 平时它不亮(不工作);

② 一旦有人走到门口(也就是表里发生了 INSERT/UPDATE/DELETE),它自动亮起来(执行预设逻辑)。

和上一章学的"存储过程"对比:存储过程要你手动 CALL 才跑;触发器是自动跑,这是它俩最大的不同。

两个时机:BEFORE 还是 AFTER?

触发器只有两种触发时机,记住它们各自擅长什么就行:

🛡️BEFORE 触发器

在数据操作 之前 执行。

擅长:先检查、先修改(趁数据还没写进去,做点处理)。

例:插入成绩为空时,先改成 0 再存。

📝AFTER 触发器

在数据操作 之后 执行。

擅长:记一笔、做后续(数据已经写好了,再去做关联的事)。

例:改完专业后,往日志表记一条。

🧠记住
先校验,用 BEFORE;后记录,用 AFTER。
想"动手改数据"就赶在前面;想"留个记录"就放在后面。

触发器里最关键的两个词:NEW 和 OLD

触发器要操作的是"正在被改的那一行"。可问题是 —— 怎么拿到这行的新值和旧值?答案就是这两个特殊的词:

📖 NEW 和 OLD 是什么

NEW = 这次操作的 新数据(正要插入的、或修改后的)。

OLD = 这次操作的 旧数据(修改前的、或将被删除的)。

用法很简单:NEW.字段名OLD.字段名,比如 NEW.scoreOLD.maj

但不是任何时候都有 NEW 和 OLD。这张表是全章唯一需要稍微记一下的点

操作NEW(新值)OLD(旧值)怎么理解
INSERT 插入✅ 有❌ 没有新加进来的,没有"以前"
UPDATE 修改✅ 有✅ 有改之前、改之后,两头都在
DELETE 删除❌ 没有✅ 有要删掉了,只剩"以前"
🧠记住
插入用 NEW,删除用 OLD,修改两个都能用。
在 INSERT 里写 OLD、或在 DELETE 里写 NEW 都会报错。

看一个完整例子:自动把空成绩补成 0

需求:往成绩表 sc 插数据时,如果成绩 score 是空的,自动改成 0 再存进去。

SQL · BEFORE INSERT
DELIMITER $$

CREATE TRIGGER trg_fill_score
BEFORE INSERT ON sc
FOR EACH ROW
BEGIN
    IF NEW.score IS NULL THEN
        SET NEW.score = 0;
    END IF;
END $$

DELIMITER ;
BEFORE INSERT ON sc:在往 sc 表插数据之前 触发。
NEW.score:拿到这次要插入的新成绩。
精髓所在:在 BEFORE 里 SET NEW.score = 0,是真的能改掉将要写进去的值的!
④ 于是插入的 NULL 最后变成了 0 存进库里。
⚠️ 一个必须养成的习惯:DELIMITER

触发器内部有多条以 ; 结尾的语句。和存储过程一样,要先用 DELIMITER $$ 把结束符临时改成 $$,写完再 DELIMITER ; 改回来。忘了它就会报错。

再看一眼:改完专业,自动记一笔日志

需求:学生改了专业(maj 字段),自动把"改前 → 改后"记到日志表。这是 AFTER 触发器最典型的用法,也是唯一会同时用上 OLD 和 NEW 的场景。

SQL · AFTER UPDATE
DELIMITER $$

CREATE TRIGGER trg_log_maj
AFTER UPDATE ON s
FOR EACH ROW
BEGIN
    INSERT INTO maj_log VALUES
    (OLD.sno, OLD.maj, NEW.maj, NOW());
END $$

DELIMITER ;
· OLD.maj改之前的专业,NEW.maj改之后的专业 —— 一句话就把变化记清楚了。
· 用 AFTER 是因为:我们想"记录已经发生的事",数据改完了再记最自然。
💡 顺带一提(了解即可,不用记)

触发器还能做"级联删除"—— 比如删一个学生时,用 BEFORE DELETE 配合 OLD.sno 把他的选课记录一起删掉。原理和上面一样,换个时机和操作而已。另外:触发器不能用 ALTER 改,要改只能"先 DROP 再重建"。

📋 触发器固定模板(套着写就行)
CREATE TRIGGER 触发器名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON 表名
FOR EACH ROW
BEGIN
    -- 这里写触发时要执行的 SQL
END
2

事件:时间的"定时器"

不看数据动不动,只看时间 —— 到点了就自动执行

先用一句话 + 一个浇花器理解它

📖 定义

事件是一个"到指定时间(或每隔一段时间)就自动执行"的任务。可以把它看成数据库自带的一个闹钟/定时器。

🌰 触发器 vs 事件,一对好对比

触发器像"红外感应灯" —— 有人来了才亮(数据被改才动)。

事件像"定时浇花器" —— 到点就喷水(不管有没有人,时间到了就干活)。

用事件之前:先把"调度器"打开

事件由数据库里一个叫"事件调度器"的开关统一管理。这个开关默认是关的 —— 不打开,你写的事件就只是躺着,不会真的跑。

SQL · 调度器开关
-- 看看现在是开还是关
SHOW VARIABLES LIKE 'event_scheduler';

-- 打开它(关键一步!)
SET GLOBAL event_scheduler = ON;
🧠记住
事件不跑?先检查调度器开了没。
这是初学者第一大坑:代码全对,就因为 event_scheduler = OFF

两种时间写法:AT(一次)和 EVERY(周期)

创建事件的模板很短,重点就是中间那行"时间怎么安排",只有两种:

📋 事件固定模板
CREATE EVENT 事件名
ON SCHEDULE 时间安排      ← 这里二选一:AT 或 EVERY
DO
    -- 要执行的 SQL
⏰ AT —— 一次性

在某个时刻执行一次,跑完就没了。

AT '2025-12-31 23:59:59'
AT NOW() + INTERVAL 10 SECOND
🔁 EVERY —— 周期性

每隔一段时间执行一次,一直循环。

EVERY 1 DAY
EVERY 1 WEEK
🧠记住
AT = "在某时",跑一次;EVERY = "每隔",反复跑。

看一个例子:每周自动清空临时表

需求:临时表 tb_temp 容易堆垃圾数据,希望 每周自动清空一次

SQL · 周期性事件
CREATE EVENT evt_weekly_clean
ON SCHEDULE EVERY 1 WEEK
DO
    DELETE FROM tb_temp;
· EVERY 1 WEEK:每隔一周触发一次。
· DO 后面跟要做的事。如果不止一条 SQL,就用 BEGIN…END 包起来(这时也要配 DELIMITER)。
· 不想要了?DROP EVENT IF EXISTS evt_weekly_clean; 即可。
3

一张图看懂:它俩到底差在哪

本章最该带走的一页 —— 看懂这张图,这章就过关了

触发器 TRIGGER

表的 INSERT / UPDATE / DELETE

有 BEFORE/AFTER,能用 NEW/OLD

"有人动,才反应"
VS

事件 EVENT

时间到了(AT / EVERY)

要先开调度器,没有 NEW/OLD

"到点了,就干活"
对比项触发器 TRIGGER事件 EVENT
谁来触发对表做 增 / 改 / 删到了某个时间点
关键词BEFORE / AFTERAT / EVERY
能用 NEW/OLD 吗✅ 能❌ 不能
典型用途校验数据 / 记日志 / 级联定时清理 / 定时统计 / 定时备份
🧠一句话
触发器看"数据变化",事件看"时间到点"。
分不清用哪个?就问自己:是"某个操作"触发,还是"某个时刻"触发?

三句话带走这一章

合上页面前,在心里默念一遍
🎯 记住这三句,就够了
  1. 触发器 = 数据的自动反应。表一被 增/改/删 就跑,靠 BEFORE/AFTER 选时机、靠 NEW/OLD 拿新旧值。
  2. 事件 = 时间的定时器。靠 AT(一次)/ EVERY(周期) 安排时间,记得先开调度器
  3. 两者都让数据库"自己干活",区别只在于:一个被数据触发,一个被时间触发